
#include <stdio.h>
/**
 * ************************************************************************
 * @brief 普通模式做法
 * ************************************************************************

void stopPlayer();
void pausePlayer();
void resumePlayer();
void startPlayer();
//按键的动作类型
typedef enum {
    EV_STOP,
    EV_PLAY_PAUSE
}EventCode;
 
//MP3的状态
enum{
  ST_IDLE,
  ST_PLAY,
  ST_PAUSE
};
 
//MP3当前状态
char state;
 
//MP3状态初始化
void init()
{
  state = ST_IDLE;
}
 
//状态机处理MP3的过程变化
void onEvent(EventCode ec)
{
  switch (state)
  {
  case ST_IDLE:
        if(EV_PLAY_PAUSE == ec)
          startPlayer();
        break;
  case ST_PLAY:
        if(EV_STOP == ec)
          stopPlayer();
        else if(EV_PLAY_PAUSE == ec)
          pausePlayer();
        break;
  case ST_PAUSE:
        if(EV_STOP == ec)
          stopPlayer();
        else if(EV_PLAY_PAUSE == ec)
          resumePlayer();
        break;
  default:
        break;
  }
}
 
void stopPlayer()
{
  state = ST_IDLE;
  printf("停止播放音乐\n");
}
 
void pausePlayer()
{
  state = ST_PAUSE;
  printf("暂停播放音乐\n");
}
 
void resumePlayer()
{
  state = ST_PLAY;
  printf("恢复播放音乐\n");
}
 
void startPlayer()
{
  state = ST_PLAY;
  printf("开始播放音乐\n");
}
//主程序实现MP3的播放控制
void main()
{
  init();
  onEvent(EV_PLAY_PAUSE);//播放
  onEvent(EV_PLAY_PAUSE);//暂停
  onEvent(EV_PLAY_PAUSE);//继续播放
  onEvent(EV_STOP);      //停止
}
  */

 /**
  * ************************************************************************
  * @brief 状态机做法
  * ************************************************************************
  */
 
/***********************************************
1、定义状态接口，以MP3的状态接口为例，每种状态下都可能发生
两种按键动作。
************************************************/
 
typedef struct State{
  void (* stop)();
  void (* palyOrPause)();
}State;
 
 
/***********************************************
2、定义系统当前状态指针，保存系统的当前状态
************************************************/
 
State * pCurrentState;
 
 
/***********************************************
3、定义具体状态，根据状态迁移图来实现具体功能和状态切换。
************************************************/
 
void ignore();
void startPlay();
void stopPlay();
void pausePlay();
void resumePlay();
 
//空闲状态时，stop键操作无效，play/pause会开始播放音乐
State IDLE = {
  ignore,
  startPlay
};
 
//播放状态时，stop键会停止播放音乐，play/pause会暂停播放音乐
State PLAY = {
  stopPlay,
  pausePlay
};
 
//暂停状态时，stop键会停止播放音乐，play/pause会恢复播放音乐
State PAUSE = {
  stopPlay,
  resumePlay
};
 
void ignore()
{
  //空函数，不进行操作
}
 
void startPlay()
{
  //实现具体功能
  printf("开始播放音乐\n");
  //进入播放状态
  pCurrentState = &PLAY;
}
void stopPlay()
{
  //实现具体功能
  printf("停止播放音乐\n");
  //进入空闲状态
  pCurrentState = &IDLE;
}
 
void pausePlay()
{
  //实现具体功能
  printf("暂停播放音乐\n");
  //进入暂停状态
  pCurrentState = &PAUSE;
}
 
void resumePlay()
{
  //实现具体功能
  printf("恢复播放音乐\n");
  //进入播放状态
  pCurrentState = &PLAY;
}
 
 
/***********************************************
4、定义主程序上下文操作接口，主程序只关心当前状态，不关心状态之间
是怎么变化的。
************************************************/
 
void onStop();
void onPlayOrPause();
 
State context = {
  onStop,
  onPlayOrPause
};
 
void onStop(State *pThis)
{
  pCurrentState->stop(pThis);
}
 
void onPlayOrPause(State *pThis)
{
  pCurrentState->palyOrPause(pThis);
}
 
 
/***********************************************
5、初始化系统当前状态指针，其实就是指定系统的起始状态
************************************************/
 
void init()
{
  pCurrentState = &IDLE;
}
 
/***********************************************
6、主程序通过上下文操作接口来控制系统当前状态的变化
************************************************/
void main()
{
  init();
  context.palyOrPause();//播放
  context.palyOrPause();//暂停
  context.palyOrPause();//播放
  context.stop();//停止
}